package asteroids.entity.weapon;

import org.apache.log4j.Logger;

import asteroids.engine.Utils;
import asteroids.engine.Utils.PolarCoordinate;
import asteroids.entity.GameObject;
import asteroids.entity.Ship;

public class Bullet extends GameObject
{
    private static Logger logger = Logger.getLogger(Bullet.class);

    private Ship owner;

    private int bulletTimeToLive;
    private boolean eternal = false;
    private boolean friendlyFire = false;

    static public final Utils.PolarCoordinate[] basicBulletShape = {
            Utils.createPolarCoordinate(0, -0.5), Utils.createPolarCoordinate(0, 0.5) }; // unit
                                                                                         // length,
                                                                                         // centered

    public Bullet(double xpos, double ypos, double direction, double speed, double power,
            int timeToLive, PolarCoordinate[] shape, Ship ship)
    {
        super(xpos, ypos, shape, GameObject.ObjectType.BULLET);
        Utils.CartesianCoordinate coord = Utils.cartesianFromPolar(Utils.createPolarCoordinate(
                direction, speed));
        x_speed = coord.getXComponent();
        y_speed = coord.getYComponent();
        rotation = direction;
        integrity = power;
        bulletTimeToLive = timeToLive;
        this.owner = ship;
        this.affiliation = ship.getAffiliation();
    }

    public Bullet(double x, double y, double direction, double speed, double power, int timeToLive,
            Ship ship)
    {
        this(x, y, direction, speed, power, timeToLive, basicBulletShape, ship);
    }

    public Bullet(double xpos, double ypos, double direction, double speed, double power,
            Utils.PolarCoordinate[] shape, Ship ship)
    {
        this(xpos, ypos, direction, speed, power, 0, shape, ship);
        eternal = true;
    }

    public void setFriendlyFire(boolean friendlyFire)
    {
        this.friendlyFire = (friendlyFire) ? true : false;
    }

    public void update()
    {
        alive = ((0 < bulletTimeToLive) || eternal);
        bulletTimeToLive--;
        super.update();
    }

    public boolean isAlive()
    {
        return alive;
    }

    public Utils.CartesianCoordinate[] getCollisionBounds()
    {
        Utils.CartesianCoordinate[] myPolygon = new Utils.CartesianCoordinate[objectShape.length * 2];

        if( oldObjectShape == null )
        { // decrease the size if we don't have a
          // previous position
            myPolygon = new Utils.CartesianCoordinate[objectShape.length];
        }

        for( int i = 0; i < objectShape.length; i++ )
        {
            // copy the coordinates, and rotate to reflect the current position
            myPolygon[i] = Utils.cartesianFromPolar(objectShape[i].rotateBy(rotation)).shiftBy(
                    x_position, y_position);
        }
        // now we add on the points for the previous bullet position, to prevent
        // bullets going through targets without hitting.
        if( oldObjectShape != null )
        {
            for( int i = objectShape.length; i < objectShape.length * 2; i++ )
            {
                myPolygon[i] = oldObjectShape[i - objectShape.length];
            }
        }

        return myPolygon;
    }

    @Override
    public double getCollisionPower(GameObject other)
    {
        double pow = integrity;
        // friendly fire is false by default
        if( !friendlyFire && other.getType() == GameObject.ObjectType.SHIP
                && other.getAffiliation().equals(affiliation) )
        {
            pow = 0;
        }
        return pow;
    }

    @Override
    public void collide(GameObject other, double power)
    {
        logger.trace(this + " hit " + other);
        boolean friendlyObject = ((!friendlyFire && other.getType() != GameObject.ObjectType.BULLET && other
                .getAffiliation().equals(affiliation)));

        super.collide(other, (friendlyObject) ? 0 : power);

        // if we aren't trading off with another bullet, just die (unless it's a
        // friendly ship)
        if( other.getType() != GameObject.ObjectType.BULLET && !friendlyObject )
        {
            destroy();
        }
    }

    public void destroy()
    {
        logger.trace(this + ".destroy()");
        super.destroy();
        eternal = false;
        bulletTimeToLive = 0;
    }

    @Override
    public void modifyScoreBy(int amt)
    {
        owner.modifyScoreBy(amt);
    }
}